package baduga.server;

import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.OutputStreamWriter;

import javax.net.ssl.SSLSocket;

import baduga.server.Controler;
import baduga.server.Network_Api;
import baduga.core.Core_Exception;
import baduga.core.Core_JsonDataSchema;
import baduga.core.Core_Messages;

public class Network_API__Client_Thread extends Thread {
	
	/** Socket SSL dla klienta */
	private SSLSocket clientSocketSSL;
	
	/** Bufory */
	private BufferedReader 	inboundData;
	private BufferedWriter 	outboundData; 
	
	/** Status gotowości */
	private boolean clientReadyState;
	
	/** PlayerID */
	private String playerID;
	
	
	private boolean debugMode = false;
	
	
	/** Kontroler Requestów */
	Network_Call__Controler nControler = new Network_Call__Controler();
	
	
	
	/**
	 * 
	 * @param socket
	 */
	Network_API__Client_Thread(SSLSocket socket)
	{
		clientSocketSSL = socket;
	}
	
	
	/**
	 * Konstruktor specialny
	 * 
	 * @param socket
	 * @param debug
	 */
	Network_API__Client_Thread(SSLSocket socket, boolean nDebugMode)
	{
		clientSocketSSL = socket;
		debugMode = nDebugMode;
	}
	
	
	/**
	 * 	Wątek klienta w trybie słuchania
	 * @throws IOException 
	 */
	public void invokeListening()
	{
		clientReadyState = true;
		
		try {
			
			inboundData = new BufferedReader(new InputStreamReader(clientSocketSSL.getInputStream()));
			outboundData = new BufferedWriter(new OutputStreamWriter(clientSocketSSL.getOutputStream()));
		} catch (IOException ioException) {
			//TODO: DBG_IMPROVE_FUTURE
			Core_Exception.showOwnMessage(Core_Messages.getMessage(0x0284), Core_Messages.getMessage(0x0100));
			clientReadyState = false;
		}
		
		/** Jeżeli podpięcie buforów przeszło pomyślnie to zasuwamy */
		if(clientReadyState && !debugMode)
		{

			
			String input = "";
			
			Network_Api netwAPI = Controler.getNetwAPI();
			
			/** Struktura danych */
			Core_JsonDataSchema wStructure = new Core_JsonDataSchema();
			
			try {
				while(!this.isInterrupted() &&  (input = inboundData.readLine()) != null   && clientReadyState)
				{		
					
					//TODO: DEBUG
					System.out.println("\n\n\nINBOUND: | " + input +  "| \n\n\n");
					
					
					//JSON 2 Data
					wStructure = netwAPI.decodeJson(input);

					if(wStructure  != null)
					{
						
						System.out.println("IN: \n KOD: " + wStructure .getKod()  + "| ARGS : " + wStructure .getArgs()[0]  + "| Dane: " +  wStructure .getDataD1()[0] + "\n\n");
						
						
						//Przetworzenie struktóry danych
						wStructure = nControler.globalSwitch(wStructure, this);
						
						
						System.out.println("OUT: \n KOD: " + wStructure .getKod()  + "| ARGS : " + wStructure .getArgs()[0]  + "| Dane: " +  wStructure .getDataD1()[0] + "\n\n");
						
						//Wysłanie danych
						sendData(wStructure);
						
						
					}
					

				}
			} catch (IOException e) {
				//TODO: DBG_IMPROVE_FUTURE
				Core_Exception.showOwnMessage(Core_Messages.getMessage(0x0283), Core_Messages.getMessage(0x0100));
			}
		}
		
		
	}

	
	/**
	 * Funkcja przerywa pracę wątku
	 */
	public void shutDown(boolean byeCmdToClient)
	{
		
		/** Wysłanie informacji do klienta, że jego usługa została wydalona*/
		if(byeCmdToClient)
		{
			
		}
		
		
		try
		{
			
			/** Przerwanie wątka */
			this.interrupt();
			
			clientReadyState = false;
			
			/** Zamknięcie kanałów danych*/
			inboundData.close();
			outboundData.close();
			
			/** Zamknięcie Socketa*/
			clientSocketSSL.close();
			

		}
		catch(IOException exceptionIO)
		{
			//TODO: DBG_IMPROVE_FUTURE
			Core_Exception.showOwnMessage(Core_Messages.getMessage(0x02F4), Core_Messages.getMessage(0x0100));
		}
	}
	
	
	
	
	/**
	 * Funkcja zajmuje się wysyłaniem struktóry danych do klienta
	 * 
	 * @param data
	 */
	public void sendData(final Core_JsonDataSchema data)
	{
		boolean opStatus = true;
		
		if(clientReadyState)
		{
			
			Network_Api netwAPI = Controler.getNetwAPI();
			
			String tmp = null;

			
			try {
				tmp = netwAPI.encodeJson(data);
			} catch (IOException e) {
				//TODO: DBG_IMPROVE_FUTURE
				Core_Exception.showOwnMessage(Core_Messages.getMessage(0x02F7), Core_Messages.getMessage(0x0100));
				opStatus = false;
			}
			
			if(opStatus)
			{
				//Dodanie znaku końca lini
				tmp  += '\n';
				
				try {
					System.out.println("\n\n\nOUTBOUND: | " + tmp +  "| \n\n\n");
					
					
					outboundData.write(tmp);
					
					outboundData.flush();
					//replystatus = false;
				} catch (IOException e) {
					//TODO: DBG_IMPROVE_FUTURE
					Core_Exception.showOwnMessage(Core_Messages.getMessage(0x027E), Core_Messages.getMessage(0x0100));
				}
			}
		}
		else
		{
			opStatus = false;
		}
		
		
		
	}
	
	
	
	
	
	
	/**
	 * 
	 * Funckja uruchamiająca wątek.
	 * Dodatko została dodana obsługa gracefullShutodwn
	 * 
	 */
	@Override
	public void run()
	{
		
		/**  Kiedy niespodziewanie serwer chce iśc spać */
		Runtime.getRuntime().addShutdownHook(new Thread("Gracefull Shutodwn") {
			
			@Override
			public void run() {
				//Uśpienie klienta
				shutDown(true);
			}
			
		});
		
		invokeListening();
		
		
		
	}
	
	
	/**
	 * Funkcja ustawia socket
	 * 
	 * @param nSocket
	 */
	public void setSocket(SSLSocket nSocket)
	{
		if(this.debugMode)
		{
			clientReadyState = true;
			
			clientSocketSSL = nSocket;
			invokeListening();
		}
	}
	
	
}
